package ie.lawlor.amvc.patterns.table;

import ie.lawlor.amvc.event.Event;
import ie.lawlor.amvc.patterns.standard.StandardModel;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;


/**
 * @author blawlor
 *
 */
public abstract class TableModel extends StandardModel{

	protected int selectedRow = -1;
	protected int selectedColumn = -1;
	protected Object selectedObject;
	protected List list = new ArrayList();
	protected List fields = new ArrayList();
	protected List visibleFields = new ArrayList();
	protected Comparator currentComparator;
	protected int sortField;
	protected boolean sortAscending = false;

	/**
	 * @param name
	 */
	public TableModel(String name) {
		super(name, true);
	}

	public int getSelectedRow(){
		return selectedRow;
	}

	public int getSelectedColumn(){
		return selectedColumn;
	}

	public void doSelect(Event e) {
		TableCellReference cell = (TableCellReference)e.getPayload();
		if (selectedRow != cell.row || selectedColumn != cell.column){
			selectedRow = cell.row;
			selectedColumn = cell.column;
			if (selectedRow > -1){
				selectedObject = list.get(selectedRow);
			}
			fire(getController().getEvent(TableController.SELECTION_CHANGED_EVENT),selectedObject);
			fireUpdateView();
		}
	}

	public void doObjectUpdated(Event e){
		Object updatedObject = e.getPayload();
		int index = list.indexOf(updatedObject);
		if (index > -1){
			list.set(index, updatedObject);
			fireUpdateView();
		} else {
			logger.warn("Updated object " + updatedObject + " was not in list");
		}
	}

	public void doChangeList(Event e){
		logger.debug("About to update the list to be " + e.getPayload()); 
		list = (List)e.getPayload();
		fireUpdateView();
	}

	public int getPreferredWidth(int columnIndex){
		Field field = (Field)visibleFields.get(columnIndex);
		return field.getPreferredFieldWidth();
	}

	public int getMaxWidth(int columnIndex){
		Field field = (Field)visibleFields.get(columnIndex);
		return field.getMaxFieldWidth();
	}

	public abstract Object getValueAt(int x, int y);

	public int getNumberOfRows(){
		return list.size();
	}

	public int getNumberOfFields(){
		return visibleFields.size();
	}

	public String getFieldName(int columnIndex){
		Field field = (Field)fields.get(columnIndex);
		return field.getTitle();
	}

	protected void fireListChanged(){
		fire(getController().getEvent(TableController.LIST_CHANGED_EVENT), list);
	}

	protected void addField(Field field){
		fields.add(field);
		if (field.isVisible()){
			visibleFields.add(field);
		}
	}

	protected static class Field {
		public static final int NO_SORT = 0;
		public static final int SORT = 1;
		public static final int REVERSE_SORT = 2;
		int fieldId;
		boolean visible;
		int sort = NO_SORT;
		int maxFieldWidth;
		int preferredFieldWidth;
		String title;

		public Field(int fieldId, boolean visible) {
			this.fieldId = fieldId;
			this.visible = visible;
		}

		public Field(int fieldId, String title, boolean visible, int max, int pref) {
			this.fieldId = fieldId;
			this.visible = visible;
			this.title = title;
			this.maxFieldWidth = max;
			this.preferredFieldWidth = pref;
		}

		public boolean isVisible() {
			return visible;
		}

		public void setVisible(boolean visible) {
			this.visible = visible;
		}

		public int getFieldId() {
			return fieldId;
		}

		public int getSort() {
			return sort;
		}

		public void setSort(int sort) {
			this.sort = sort;
		}

		public int hashCode() {
			return fieldId;
		}

		public String getTitle(){
			return title;
		}

		public void setTitle(String title){
			this.title = title;
		}

		public int getMaxFieldWidth() {
			return maxFieldWidth;
		}
		public void setMaxFieldWidth(int maxFieldWidth) {
			this.maxFieldWidth = maxFieldWidth;
		}
		public int getPreferredFieldWidth() {
			return preferredFieldWidth;
		}
		public void setPreferredFieldWidth(int preferredFieldWidth) {
			this.preferredFieldWidth = preferredFieldWidth;
		}
		public boolean equals(Object o) {
			if (o instanceof Field) {
				Field tf = (Field) o;

				return (tf.getFieldId() == getFieldId());
			} else {
				return false;
			}
		}
	}


}
